android 7.0 系统通知发送失败

项目中突然某一天发现在Android 7.0上后台收不到消息通知了,错误提示如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java.lang.SecurityException: You need MANAGE_USERS permission to: check if specified user a managed profile outside your profile group
at android.os.Parcel.readException(Parcel.java:1683)
at android.os.Parcel.readException(Parcel.java:1636)
at android.os.IUserManager$Stub$Proxy.isManagedProfile(IUserManager.java:1521)
at android.os.UserManager.isManagedProfile(UserManager.java:888)
at android.app.ApplicationPackageManager.isManagedProfile(ApplicationPackageManager.java:2363)
at android.app.ApplicationPackageManager.getManagedProfileIconForDensity(ApplicationPackageManager.java:1219)
at android.app.ApplicationPackageManager.getUserBadgeForDensityNoBackground(ApplicationPackageManager.java:1207)
at android.app.Notification$Builder.getProfileBadgeDrawable(Notification.java:3191)
at android.app.Notification$Builder.getProfileBadge(Notification.java:3196)
at android.app.Notification$Builder.bindProfileBadge(Notification.java:3210)
at android.app.Notification$Builder.bindNotificationHeader(Notification.java:3360)
at android.app.Notification$Builder.applyStandardTemplate(Notification.java:3279)
at android.app.Notification$Builder.applyStandardTemplate(Notification.java:3265)
at android.app.Notification$Builder.applyStandardTemplate(Notification.java:3254)
at android.app.Notification$Builder.createContent1View(Notification.java:3571)
at android.app.Notification$Builder.build(Notification.java:3843)

我尝试加了MANAGE_USERS权限,看起来是个系统级别权限,验证后果然无效。从报错看可能跟系统用户有关,也许关联了什么权限没有获得。开始只能通过try/catch, 这样在前台可以收到消息。那在后台还是有问题。

开始我有2个怀疑点:
1、7.0 修改了Notification的构建方式。 但查看api更新说明,没有提及。
2、当时测出问题是在Nexus6, 从这个权限名来看 MANAGE_USERS,怀疑与系统的用户管理权限有关。

后来经过很长时间终于找到这个问题的根本原因。

首先重建一个Demo在7.0上测试一切正常,说明很有可能是我们自己工程的问题,后来发现在我们工程自定义的MyApplication有一个方法叫getUserId(), 而在Notification构建时发现有一个相同的方法。

api 24(Android 7.0):

由于这个Context 在Builder构造的时候传的是Application context, 所以很大可能就是和系统方法冲突了。

但是我又看了下,7.0以前的代码也有同样的方法,只是位置略有不同,至此还是不能解释为什么只有7.0有问题。

api 23(Android 6.0):

然后我又找出framework对应的代码版本,7.0.0_r1, 有一段提交记录:

注意到有一个callingUserId != userId 的权限判断。 我猜测userId正是前面getUserId得到的, 如果用了自己代码中得到的id肯定是错误的,才会抛出这个异常。

重命名自己的getUserId方法后,通知功能一切正常,至此验证了此猜测的正确性。后面有时间再仔细研究一下这里的userId的含义以及具体是如何获取到的。

原创技术分享,您的支持将鼓励我继续创作